package com.boful.common.file.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.Date;

import org.apache.commons.codec.binary.Hex;

import cpdetector.io.ASCIIDetector;
import cpdetector.io.CodepageDetectorProxy;
import cpdetector.io.JChardetFacade;
import cpdetector.io.ParsingDetector;

public class FileUtils {
	/**
	 * 获取文件名称，没有后缀
	 * 
	 * @param fileName
	 *            原始文件名
	 * @return 文件名
	 */
	public static String getFilePrefix(String fileName) {
		int splitIndex = fileName.lastIndexOf(".");
		return fileName.substring(0, splitIndex);
	}

	/**
	 * 获取文件后缀
	 * 
	 * @param fileName
	 *            原始文件名
	 * @return 文件后缀名
	 */
	public static String getFileSufix(String fileName) {
		int splitIndex = fileName.lastIndexOf(".");
		return fileName.substring(splitIndex + 1);
	}

	/**
	 * 复制文件
	 * 
	 * @param inputFile
	 *            源文件
	 * @param outputFile
	 *            目标文件
	 * @throws FileNotFoundException
	 */
	public static void copyFile(String inputFile, String outputFile)
			throws FileNotFoundException {
		File sFile = new File(inputFile);
		File tFile = new File(outputFile);
		FileInputStream fis = new FileInputStream(sFile);
		FileOutputStream fos = new FileOutputStream(tFile);
		copyFile(fis, fos);
	}

	public static void copyFile(File inputFile, File outputFile)
			throws FileNotFoundException {
		FileInputStream fis = new FileInputStream(inputFile);
		FileOutputStream fos = new FileOutputStream(outputFile);
		copyFile(fis, fos);
	}

	public static void copyFile(InputStream inputStream, File outputFile)
			throws FileNotFoundException {
		FileOutputStream fos = new FileOutputStream(outputFile);
		copyFile(inputStream, fos);
	}

	public static void copyFile(InputStream inputStream, OutputStream outputFile)
			throws FileNotFoundException {
		BufferedInputStream fis = new BufferedInputStream(inputStream);
		BufferedOutputStream fos = new BufferedOutputStream(outputFile);
		try {
			byte[] buffer = new byte[1024];
			int remaing = 0;
			while ((remaing = fis.read(buffer)) > 0) {
				fos.write(buffer, 0, remaing);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				fis.close();
				fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 取文件hash
	 * 
	 * @param file
	 * @return
	 */
	public static byte[] getHash(File file) {
		try {
			RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
			ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
			DataOutputStream dataOutputStream = new DataOutputStream(
					byteArrayOutputStream);
			dataOutputStream.writeLong(file.length());
			if (file.length() < 1024) {
				// 小于1024字节全部做hash
				byte[] buffer = new byte[(int) file.length()];
				randomAccessFile.read(buffer);
				dataOutputStream.write(buffer);
			} else {
				// 大于1024取文件首、中、尾的16个字节做hash
				byte[] buffer = new byte[16];
				randomAccessFile.read(buffer);
				dataOutputStream.write(buffer);
				System.out.println(Arrays.toString(buffer));
				System.out.println(buffer.length);
				randomAccessFile.seek(file.length() / 2);
				randomAccessFile.read(buffer);
				dataOutputStream.write(buffer);
				System.out.println(Arrays.toString(buffer));
				System.out.println(buffer.length);
				randomAccessFile.seek(file.length() - 16 - 1);
				randomAccessFile.read(buffer);
				dataOutputStream.write(buffer);
				System.out.println(Arrays.toString(buffer));
				System.out.println(buffer.length);
			}
			byte[] buf = byteArrayOutputStream.toByteArray();
			System.out.println(Arrays.toString(buf));
			System.out.println(buf.length);
			randomAccessFile.close();
			byteArrayOutputStream.close();
			dataOutputStream.close();
			return EncoderUtils.md5(buf);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static String getHexHash(File file) {
		byte[] hash = getHash(file);
		return Hex.encodeHexString(hash).toUpperCase();
	}

	/***
	 * 转换字符文件到UTF-8
	 * 
	 * @param src
	 *            字符文件
	 * @param dest
	 *            输出文件可以和src一致
	 */
	public static void convertToUTF8(File src, File dest) throws Exception {
		String encoding = getEncoding(src);
		if (!encoding.equals("UTF-8")) {
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					new FileInputStream(src), encoding));
			File file = File.createTempFile("boful-" + new Date().getTime(),
					"tmp");

			OutputStreamWriter writer = new OutputStreamWriter(
					new FileOutputStream(file), "UTF-8");
			String line = null;

			while ((line = reader.readLine()) != null) {
				writer.write(line + "\n\r");

			}
			reader.close();
			writer.close();

			copyFile(file, dest);
		} else {
			copyFile(src, dest);
		}

	}

	/***
	 * 获取字符串编码
	 * 
	 * @param str
	 * @return 编码格式
	 */
	public static String getEncoding(String str) {
		String encode = "GB2312";
		try {
			if (str.equals(new String(str.getBytes(encode), encode))) {
				String s = encode;
				return s;
			}
		} catch (Exception exception) {
		}
		encode = "ISO-8859-1";
		try {
			if (str.equals(new String(str.getBytes(encode), encode))) {
				String s1 = encode;
				return s1;
			}
		} catch (Exception exception1) {
		}
		encode = "UTF-8";
		try {
			if (str.equals(new String(str.getBytes(encode), encode))) {
				String s2 = encode;
				return s2;
			}
		} catch (Exception exception2) {
		}
		encode = "GBK";
		try {
			if (str.equals(new String(str.getBytes(encode), encode))) {
				String s3 = encode;
				return s3;
			}
		} catch (Exception exception3) {
		}
		return "";
	}

	/***
	 * 获取字符文件编码
	 * 
	 * @param file
	 * @return
	 */
	public static String getEncoding(File file) {
		try {
			BufferedReader reader = new BufferedReader(new FileReader(file));
			String line = reader.readLine();
			reader.close();
			return getEncoding(line);
		} catch (Exception e) {
			return "";
		}
	}

	public static void nioCopy(File src, File dest) {
		try {
			FileInputStream fileInputStream = new FileInputStream(src);
			FileOutputStream fileOutputStream = new FileOutputStream(dest);
			FileChannel inChannel = fileInputStream.getChannel();
			FileChannel outChannel = fileOutputStream.getChannel();
			inChannel.transferTo(0, src.length(), outChannel);

			fileInputStream.close();
			inChannel.close();
			fileOutputStream.close();
			outChannel.close();
		} catch (Exception exception) {
			exception.printStackTrace();
		}

	}

	public static String getFileEncode(File file) {
		/*
		 * detector是探测器，它把探测任务交给具体的探测实现类的实例完成。
		 * cpDetector内置了一些常用的探测实现类，这些探测实现类的实例可以通过add方法 加进来，如ParsingDetector、
		 * JChardetFacade、ASCIIDetector、UnicodeDetector。
		 * detector按照“谁最先返回非空的探测结果，就以该结果为准”的原则返回探测到的
		 * 字符集编码。使用需要用到三个第三方JAR包：antlr.jar、chardet.jar和cpdetector.jar
		 * cpDetector是基于统计学原理的，不保证完全正确。
		 */
		CodepageDetectorProxy detector = CodepageDetectorProxy.getInstance();
		/*
		 * ParsingDetector可用于检查HTML、XML等文件或字符流的编码,构造方法中的参数用于
		 * 指示是否显示探测过程的详细信息，为false不显示。
		 */
		detector.add(new ParsingDetector(false));
		/*
		 * JChardetFacade封装了由Mozilla组织提供的JChardet，它可以完成大多数文件的编码
		 * 测定。所以，一般有了这个探测器就可满足大多数项目的要求，如果你还不放心，可以
		 * 再多加几个探测器，比如下面的ASCIIDetector、UnicodeDetector等。
		 */
		detector.add(JChardetFacade.getInstance());// 用到antlr.jar、chardet.jar
		// ASCIIDetector用于ASCII编码测定
		detector.add(ASCIIDetector.getInstance());
		// UnicodeDetector用于Unicode家族编码的测定
		// detector.add(UnicodeDetector.getInstance());
		java.nio.charset.Charset charset = null;

		try {
			charset = detector.detectCodepage(file.toURI().toURL());
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		if (charset != null)
			return charset.name();
		else
			return null;
	}

	/***
	 * 将文件变成二进制字节
	 * 
	 * @param file
	 * @return 二进制字节数组
	 */
	public static byte[] readFileAsBlob(File file) {
		byte[] buffer = new byte[(int) file.length()];
		try {
			FileInputStream fis = new FileInputStream(file);
			int r;
			int i = 0;
			while ((r = fis.read()) != -1) {
				buffer[i++] = (byte) r;
			}
			fis.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return buffer;

	}

	public static String md5Buffer(File file) {
		byte[] buffer = readFileAsBlob(file);
		byte[] encodeBuffer = EncoderUtils.md5(buffer);
		return Hex.encodeHexString(encodeBuffer);
	}

	public static void main(String[] args) throws Exception {
		File file = new File("E:/绘图1.vsdx");
		System.out.println(getHexHash(file));
		// System.out.println(md5Buffer(file));
	}
}
